package com.yzs.base.utils

import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.PathUtils
import java.io.File
import java.io.FileInputStream
import java.io.InputStream

/**
 * yzs
 * 12/31/20.
 *
 * App 文件帮助类
 *
 */
class FileHelper {
    companion object {
        // region 目录常量
        private const val DIR_GSY_VIDEO: String = "app_gsy_video"
        private const val DIR_PICTURE = "app_picture"
        private const val DIR_VIDEO = "app_video"
        private const val DIR_AUDIO = "app_audio"
        // endregion


        // region 常用路径
        /**
         * 获取内存应用数据路径
         */
        fun getAppDataPath(): String? {
            return PathUtils.getInternalAppFilesPath()
        }

        /**
         * 获取 App 内 cache 目录下的  Pictures
         * /storage/emulated/0/Android/data/(package_name)/cache/Pictures/app_picture
         * @return
         */
        fun getAppCacheDataImagePath(): String? {
            val dir = PathUtils.getExternalAppCachePath() + File.separator + DIR_PICTURE
            val orExistsDir = FileUtils.createOrExistsDir(dir)
            return if (!orExistsDir) getAppDataPath() else dir
        }


        /**
         * 获取 App 内 files 目录下的  Pictures
         * /storage/emulated/0/Android/data/(package_name)/files/Pictures/app_picture
         * @return
         */
        fun getAppDataImagePath(): String? {
            val dir = PathUtils.getExternalAppPicturesPath() + File.separator + DIR_PICTURE
            val orExistsDir = FileUtils.createOrExistsDir(dir)
            return if (!orExistsDir) getAppDataPath() else dir
        }

        /**
         * 获取 App 内 files 目录下的  Movies
         * /storage/emulated/0/Android/data/(package_name)/files/Movies/app_video
         */
        fun getAppDataVideoPath(): String? {
            val dir =
                PathUtils.getExternalAppMoviesPath() + File.separator + DIR_VIDEO
            val orExistsDir = FileUtils.createOrExistsDir(dir)
            return if (!orExistsDir) getAppDataPath() else dir
        }

        /**
         * 获取 App 内 files 目录下的  Movies
         * /storage/emulated/0/Android/data/(package_name)/files/Movies/app_video
         */
        fun getAppDataAudioPath(): String? {
            val dir = PathUtils.getExternalAppMusicPath() + File.separator + DIR_AUDIO
            val orExistsDir = FileUtils.createOrExistsDir(dir)
            return if (!orExistsDir) getAppDataPath() else dir
        }


        /**
         * 获取应用沙箱路径/cache下的文件
         *
         * @param context 上下文
         * @param name    文件路径/文件名
         * @return 文件
         */
        fun getDiskCacheFile(name: String): File {
            val path = PathUtils.getInternalAppCachePath()
            FileUtils.createOrExistsDir(path)
            val file = File(path, name)
            val dir = file.parentFile
            if (!dir.exists()) {
                dir.mkdirs()
            }
            return file
        }

        // endregion

        // region 将文件写入到外部媒体文件夹
        /**
         * 插入文件到 相册 PICTURES
         *
         * [srcFile] 表示原始的文件  源文件 File
         * [saveAlbumFileName] 需要保存到相册的图片名 FileUtils.getFileName(file)
         */
        fun insert2AlbumPictures(
            context: Context,
            srcFile: File,
            saveAlbumFileName: String
        ): Boolean {
            if (!srcFile.exists()) return false
            // 构建文件输入流
            val inputStream = FileInputStream(srcFile) ?: return false
            val uri = generateUri(
                context,
                Environment.DIRECTORY_PICTURES,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                saveAlbumFileName
            )
            //写入文件------->(3)
            return write2File(context, uri, inputStream)
        }

        /**
         * 插入文件到 视频 MOVIES
         *
         * [srcFile] 表示原始的文件  源文件 File
         * [saveAlbumFileName] 需要保存到相册的图片名 FileUtils.getFileName(file)
         */
        fun insert2AlbumMovies(
            context: Context,
            srcFile: File,
            saveAlbumFileName: String
        ): Boolean {
            if (!srcFile.exists()) return false
            // 构建文件输入流
            val inputStream = FileInputStream(srcFile) ?: return false
            val uri = generateUri(
                context,
                Environment.DIRECTORY_MOVIES,
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                saveAlbumFileName
            )
            // 写入文件-------> (3)
            return write2File(context, uri, inputStream)
        }

        /**
         *
         * 写入文件
         * [uri] 关联着待写入的文件
         * [inputStream] 表示原始的文件流
         */
        private fun write2File(
            context: Context,
            uri: Uri?,
            inputStream: InputStream?
        ): Boolean {
            if (uri == null || inputStream == null) return false
            try {
                //从Uri构造输出流
                val outputStream = getContentResolver(context).openOutputStream(uri) ?: return false
                val `in` = ByteArray(2048/*1024*/)
                var len = 0
                do {
                    //从输入流里读取数据
                    len = inputStream.read(`in`)
                    if (len != -1) {
                        outputStream.write(`in`, 0, len)
                        outputStream.flush()
                    }
                } while (len != -1)
                inputStream.close()
                outputStream.close()
            } catch (e: Exception) {
                Log.d("write2File", "写入文件失败 ${e.localizedMessage}")
                return false
            }
            return true
        }

        /**
         * 生成 Uri
         * [environmentDirType] 目录 ：Environment.DIRECTORY_PICTURES
         * [mediaExternalContentUri] EXTERNAL_CONTENT_URI ：MediaStore.Images.Media.EXTERNAL_CONTENT_URI
         * [saveAlbumFileName] 存储到共有目录的文件名
         */
        private fun generateUri(
            context: Context,
            environmentDirType: String,
            mediaExternalContentUri: Uri,
            saveAlbumFileName: String
        ): Uri? {
            val contentValues = ContentValues()
            contentValues.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, saveAlbumFileName)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                // RELATIVE_PATH 字段表示相对路径-------->(1)
                contentValues.put(
                    MediaStore.MediaColumns.RELATIVE_PATH, // 类型 ：MediaStore.Images.ImageColumns.RELATIVE_PATH 最终指向 "relative_path"
                    environmentDirType // 公共目录类型 Environment.DIRECTORY_PICTURES
                )
            } else {
                val dstPath = (Environment.getExternalStorageDirectory().toString()
                        + File.separator + environmentDirType
                        + File.separator + saveAlbumFileName)
                // DATA字段在Android 10.0 之后已经废弃
                contentValues.put(MediaStore.Images.ImageColumns.DATA, dstPath)
            }

            // 插入 Album -------> (2)
            return getContentResolver(context).insert(
                mediaExternalContentUri,
                contentValues
            )
        }

        private fun getContentResolver(context: Context): ContentResolver {
            return context.contentResolver
        }

        // endregion
    }
}